package com.hexacta.hrs.services.employee.impl;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Set;

import org.vectrics.common.util.DateUtil;
import org.vectrics.employee.Employee;
import org.vectrics.employee.MedicalInsurance;
import org.vectrics.user.Person;
import org.vectrics.user.User;

import com.hexacta.hrs.repositories.RecordObjectRepository;
import com.hexacta.hrs.repositories.employee.EmployeeRepository;
import com.hexacta.hrs.services.employee.EmployeeService;
import com.hexacta.hrs.timeoff.AvailableLicenseDays;

import edu.emory.mathcs.backport.java.util.Collections;

/**
 * Implementaci�n de {@link EmployeeService}.
 * 
 * @author mfunes
 * 
 */
class EmployeeServiceImpl implements EmployeeService {

    /** un {@link RecordObjectRepository} a usar. */
    private EmployeeRepository employeeGenericRepository;

    public void setEmployeeGenericRepository(final EmployeeRepository employeeGenericRepository) {
        this.employeeGenericRepository = employeeGenericRepository;
    }

    private RecordObjectRepository<AvailableLicenseDays> availableLicenseDaysGenericRepository;

    public void setAvailableLicenseDaysGenericRepository(
            final RecordObjectRepository<AvailableLicenseDays> availableLicenseDaysGenericRepository) {
        this.availableLicenseDaysGenericRepository = availableLicenseDaysGenericRepository;
    }

    /** {@inheritDoc} */
    public Collection<Employee> getAll() {
        return employeeGenericRepository.all();
    }

    /** {@inheritDoc} */
    public Employee searchById(final Long id) {
        if (id == null)
            return null;
        return employeeGenericRepository.forId(id);
    }

    /** Gets only employees in dependency relation */
    public Collection<Employee> getEmployeesOnly() {
        List<Employee> employeesOnlyList = new ArrayList<Employee>();
        Collection<Employee> allEmployeesList = employeeGenericRepository.all();
        for (Employee e : allEmployeesList) {

            if (e.getCurrentStatus() != null && e.getCurrentStatus().getStatusType().getIsEmployee()) {
                employeesOnlyList.add(e);
            }
        }
        Collections.sort(employeesOnlyList, new Comparator<Employee>() {

            @Override
            public int compare(final Employee o1, final Employee o2) {
                return o1.getPerson().getName().compareTo(o2.getPerson().getName());
            }

        });

        return employeesOnlyList;
    }

    /** {@inheritDoc} */
    public Collection<Employee> getNoLongerEmployees() {
        Employee criteria = new Employee();
        criteria.setDateEnd(DateUtil.getCurrentDate());
        return employeeGenericRepository.matching(criteria);
    }

    @Override
    public List<MedicalInsurance> getEmployeesMedicalInsurance() {
        return employeeGenericRepository.getEmployeesMedicalInsurance();
    }

    /**
     * {@inheritDoc} TODO deber�a recibir un EmployeeDTO m�s que el objeto
     * completo. Debido a ello se mantiene Employee como par�metro.
     */
    public EmploymentConditionDTO getCurrentEmploymentCondition(final Employee employee) {
        Date currentDate = Calendar.getInstance().getTime();
        EmploymentConditionDTO result;
        result = EmploymentConditionDTOAssembler.assembleEmploymentConditionDTO(
                employee.getEmploymentConditionHistory(), currentDate);
        return result;
    }

    /**
     * {@inheritDoc} TODO deber�a recibir un EmployeeDTO m�s que el objeto
     * completo. Debido a ello se mantiene Employee como par�metro.
     */
    public Set<EmploymentConditionDTO> getEmploymentConditionHistory(final Employee employee) {
        Set<EmploymentConditionDTO> result = null;
        if (employee.getEmploymentConditionHistory() != null) {
            result = EmploymentConditionDTOAssembler.assembleEmploymentConditionsDTO(employee
                    .getEmploymentConditionHistory());
        }
        return result;
    }

    @Override
    public void remove(Employee employee) {
        employee = employeeGenericRepository.forId(employee.getId());
        AvailableLicenseDays criteria = new AvailableLicenseDays();
        criteria.setEmployee(employee);
        Collection<AvailableLicenseDays> availableLicenseDays = availableLicenseDaysGenericRepository
                .matching(criteria);
        for (AvailableLicenseDays availableLicenseDay : availableLicenseDays) {
            availableLicenseDaysGenericRepository.delete(availableLicenseDay);
        }

        employeeGenericRepository.delete(employee);
        employeeGenericRepository.all();
    }

    /** {@inheritDoc} */
    @Override
    public Collection<Employee> getAllCurrentEmployees() {

        List<Employee> employeesOnlyList = (List<Employee>) employeeGenericRepository.getActiveEmployees();
        Collections.sort(employeesOnlyList, new Comparator<Employee>() {

            @Override
            public int compare(final Employee o1, final Employee o2) {
                return o1.getPerson().getName().compareTo(o2.getPerson().getName());
            }

        });
        return employeesOnlyList;
    }

    @Override
    public Collection<Employee> getAssignableEmployees() {
        return employeeGenericRepository.getAssignableEmployees();
    }

    /** {@inheritDoc} */
    @Override
    public Employee searchBy(final User user) {
        return employeeGenericRepository.searchBy(user);
    }

    /** {@inheritDoc} */
    @Override
    public void update(final Employee employee) {
        employeeGenericRepository.save(employee);
    }

    public Employee searchByPerson(final Person person) {
        Employee criteria = new Employee();
        criteria.setPerson(person);
        Collection<Employee> employees = employeeGenericRepository.matching(criteria);
        if (employees.iterator().hasNext())
            return employees.iterator().next();
        return null;
    }

    @Override
    public Collection<Employee> getEmployeesBetweenDates(final Date dateFrom, final Date dateTo) {
        Employee criteria = new Employee();
        criteria.setDateStart(dateFrom);
        Collection<Employee> employees = getAll();
        Collection<Employee> result = new ArrayList<Employee>();

        for (Employee employeeIt : employees) {
            if (employeeIt.getDateEnd() == null || DateUtil.isBetween(employeeIt.getDateEnd(), dateFrom, dateTo)) {
                result.add(employeeIt);
            }
        }
        return result;
    }

    @Override
    public Collection<Employee> getEmployeesAssignableToProject(final boolean onlyAssignableToProject) {
        if (onlyAssignableToProject)
            return getAssignableEmployees();
        else
            return getAllCurrentEmployees();
    }

    @Override
    public void save(final Employee employee) {
        employeeGenericRepository.save(employee);
    }

    @Override
    public Collection<Employee> getEmployeesAssignableToProject(final boolean onlyElegibleAsProjectMember,
            final Date from, final Date to, final String[] roles) {
        if (onlyElegibleAsProjectMember)
            return getAssignableEmployees(from, to, roles);
        else
            return getActiveEmployees(from, to, roles);
    }

    @Override
    public Collection<Employee> getEmployeesAssignableToProject(final boolean onlyElegibleAsProjectMember,
            final Date from, final Date to) {
        if (onlyElegibleAsProjectMember)
            return getAssignableEmployees(from, to);
        else
            return getActiveEmployees(from, to);
    }

    /**
     * @param from
     * @param to
     * @return
     */
    private Collection<Employee> getActiveEmployees(final Date from, final Date to) {
        return employeeGenericRepository.getActiveEmployees(from, to);
    }

    /**
     * @param from
     * @param to
     * @param roles
     * @return
     */
    private Collection<Employee> getActiveEmployees(final Date from, final Date to, final String[] roles) {
        return employeeGenericRepository.getActiveEmployees(from, to, roles);
    }

    /**
     * @param from
     * @param to
     * @return
     */
    private Collection<Employee> getAssignableEmployees(final Date from, final Date to) {
        return employeeGenericRepository.getAssignableEmployees(from, to);

    }

    /**
     * @param from
     * @param to
     * @param roles
     * @return
     */
    private Collection<Employee> getAssignableEmployees(final Date from, final Date to, final String[] roles) {
        return employeeGenericRepository.getAssignableEmployees(from, to, roles);

    }

    // Metodos para los reportes

    @Override
    public List<Object> getEmployeesByOffice() {
        return employeeGenericRepository.getEmployeesByOffice();
    }

    @Override
    public List<Object> getEmployeesByGender() {
        return employeeGenericRepository.getEmployeesByGender();
    }

    @Override
    public List<Object> getEmployeesMarried() {
        return employeeGenericRepository.getEmployeesMarried();
    }

    @Override
    public List<Object> getEmployeesWithChildren() {
        return employeeGenericRepository.getEmployeesWithChildren();
    }

    @Override
    public List<Object> getEmployeesByJourney() {
        return employeeGenericRepository.getEmployeesByJourney();
    }

    @Override
    public List<Object> getEmployeesByDegree() {
        return employeeGenericRepository.getEmployeesByDegree();
    }

    @Override
    public List<Object> getEmployeesBySeniorityAndArea() {
        return employeeGenericRepository.getEmployeesBySeniorityAndArea();
    }

    @Override
    public List<Object> getEmployeesBySeniorityAndGender() {
        return employeeGenericRepository.getEmployeesBySeniorityAndGender();
    }

    @Override
    public List<Object> getEmployeesByLanguage() {
        return employeeGenericRepository.getEmployeesByLanguage();
    }

    @Override
    public List<Object> getEmployeesByEnglishLevel() {
        return employeeGenericRepository.getEmployeesByEnglishLevel();
    }

    @Override
    public List<Object> getEmployeesByAntiquity() {
        return employeeGenericRepository.getEmployeesByAntiquity();
    }

    @Override
    public List<Object> getEmployeesByAge() {
        return employeeGenericRepository.getEmployeesByAge();
    }

    @Override
    public List<Object> getEmployeesFlow(final Calendar begin, final Calendar end) {
        return employeeGenericRepository.getEmployeesFlow(begin, end);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.hexacta.hrs.services.employee.EmployeeService#getEnteringEmployees
     * (java.util.Calendar, java.util.Calendar)
     */
    @Override
    public String getEnteringEmployees(final Calendar begin, final Calendar end) {
        return employeeGenericRepository.getEnteringEmployees(begin, end);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.hexacta.hrs.services.employee.EmployeeService#getExitingEmployees
     * (java.util.Calendar, java.util.Calendar)
     */
    @Override
    public String getExitingEmployees(final Calendar begin, final Calendar end) {
        return employeeGenericRepository.getExitingEmployees(begin, end);
    }

	@Override
	public List<Employee> getPartners() {
		return employeeGenericRepository.getPartners();
	}
    
    
}
